

#include "stdio.h"
#include "string.h"
#include "info.h"
#include "def.h"
#include "usart.h"
#include "jump2App.h"
#include "delay.h"
#include "flash.h"
#include "boot.h"
#include "crc.h"
#include "burn.h"
#define PROC_RESULT_BUFFER_SIZE 128

unsigned char procResult[128];
unsigned int procResultLength = 0;

typedef enum
{
    BOOT_INFO = 0x00,
    TEST = 0x01,
    ERASE = 0x02,
    BURN = 0x03,
    BURN_END = 0x04,
    CRC_BURN = 0x05,
    CRC_CHECK = 0x06,
    BURN_ACK = 0xAA,
    REBOOT = 0xF1,
    JUMP2APP = 0xF2,
    CMD_NONE = 0xFF,
} BOOTCMD;

GBool isFirmwareWrite = GFalse;

BOOTCMD gCurCmd = CMD_NONE;
//收到任意数据包都会进proc函数
void cmdProc(unsigned char *buffer, unsigned int bufferLen)
{
    uint16_t wcrc = 0;
    uint16_t caclCrc = 0;
    Burn_Parameters parm;
    if (isFirmwareWrite)
    {
        // TODO write flash
        if (buffer[0] == 0xFE && buffer[1] == 0xA5 && (buffer[2] == 0x04 && buffer[3] == 0xAA && buffer[4] == 0x58 && buffer[5] == 0xAA && buffer[6] == 0x59))
        {

            procResultLength = 0;
            memset(procResult, 0, PROC_RESULT_BUFFER_SIZE);
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = BURN_END;
            procResultLength = 3;
            gCurCmd = BURN_END;
            isFirmwareWrite = GFalse;
            burn_end();
        }
        else
        {
            burn_writePack(buffer, bufferLen);
            procResultLength = 0;
            memset(procResult, 0, PROC_RESULT_BUFFER_SIZE);
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = BURN_ACK;
            procResultLength = 3;
            gCurCmd = BURN_ACK;
        }
    }
    else if (gCurCmd != CMD_NONE)
    {
        return; //
    }
    else if (buffer[0] == 0xFE && buffer[1] == 0xA5)
    {
        procResultLength = 0;
        memset(procResult, 0, PROC_RESULT_BUFFER_SIZE);
        switch (buffer[2])
        {
        case BOOT_INFO: //返回设备基础信息
            gCurCmd = BOOT_INFO;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = BOOT_INFO;
            sprintf((char *)&procResult[3], "%s", BOOT_INFO_STR);
            procResultLength = sizeof(BOOT_INFO_STR) + 3;
            break;
        case TEST: //建立连接
            gCurCmd = TEST;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = TEST;
            procResultLength = 3;
            break;
        case ERASE: //擦除flash
            gCurCmd = ERASE;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = ERASE;
            procResultLength = 3;
            break;
        case BURN: //烧录
            // TODO reset flash write pointer and counter
            gCurCmd = BURN;
            isFirmwareWrite = GTrue;
            burn_reset();
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = BURN;
            procResultLength = 3;
            break;
        /*case BURN_END: //结束烧录
            gCurCmd = BURN_END;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = BURN_END;
            procResultLength = 3;
            break;*/
        // 烧录完毕指令不在这里操作
        case CRC_BURN: //写入CRC

            gCurCmd = CRC_BURN;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = CRC_BURN;
            procResultLength = 3;
            wcrc = buffer[3];
            wcrc <<= 8;
            wcrc |= buffer[4];
            burn_write_crc(wcrc);
            break;
        case CRC_CHECK: // CHECK CRC
            gCurCmd = CRC_CHECK;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = CRC_CHECK;
            burn_parameters_read(&parm);
            if (parm.crc == 0xFFFF || parm.firmwareSize > APP_FLASH_SIZE)
            {
                procResult[3] = 0;
            }
            else
            {
                caclCrc = crc16(APP_FLASH_ADDRESS, parm.firmwareSize);
                if (caclCrc == parm.crc)
                {
                    procResult[3] = 1;
                }
                else
                {
                    procResult[3] = 0;
                }
            }
            procResultLength = 4;
            break;
        case REBOOT: //设备重启
            gCurCmd = REBOOT;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = REBOOT;
            procResultLength = 3;
            break;
        case JUMP2APP: //强制跳转app
            gCurCmd = JUMP2APP;
            procResult[0] = 0xFE;
            procResult[1] = 0x5A;
            procResult[2] = JUMP2APP;
            procResultLength = 3;
            break;
        default:
            break;
        }
    }
}

GBool isCrcOK(void)
{
    uint16_t caclCrc;
    Burn_Parameters parm;
    burn_parameters_read(&parm);
    if (parm.crc == 0xFFFF || parm.firmwareSize > APP_FLASH_SIZE)
    {
        return GFalse;
    }
    caclCrc = crc16(APP_FLASH_ADDRESS, parm.firmwareSize);
    if (parm.crc != caclCrc)
    {
        return GFalse;
    }
    return GTrue;
}

void cmd_serivce(void)
{
    if (gCurCmd != CMD_NONE)
    {
        switch (gCurCmd)
        {
        case BOOT_INFO:
            usart_write(procResult, procResultLength);
            break;
        case TEST:
            usart_write(procResult, procResultLength);
            break;
        case ERASE:
            flash_erase(APP_FLASH_ADDRESS, APP_FLASH_SIZE);
            flash_erase(APP_PARAMETERS_ADDR, APP_PARAMETERS_SIZE);
            usart_write(procResult, procResultLength);
            break;
        case BURN:
            usart_write(procResult, procResultLength);
            break;
        case BURN_END:
            usart_write(procResult, procResultLength);
            break;
        case BURN_ACK:
            usart_write(procResult, procResultLength);
        case CRC_BURN:
            usart_write(procResult, procResultLength);
            break;
        case CRC_CHECK:
            usart_write(procResult, procResultLength);
            break;
        case REBOOT:

            usart_write(procResult, procResultLength);
            delay_ms(100);
            usart_deinit();
            NVIC_SystemReset();
            break;
        case JUMP2APP:
            if (isCrcOK())
            {
                usart_write(procResult, procResultLength);
                delay_ms(100);
                jump2APP();
            }
            break;
        case CMD_NONE:
            break;
        default:
            break;
        }
        gCurCmd = CMD_NONE;
    }
}
